/*
 * Copyright (c) 2011 Shanda Corporation. All rights reserved.
 * Development based on ZXing barcode scanner
 * 
 * Created on 2011-7-7.
 */

package com.whq.knowverywell.activity.barcode;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;

import android.app.AlertDialog;
import android.content.Intent;
import android.content.res.Resources.Theme;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
import com.google.zxing.ResultMetadataType;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ParsedResultType;
import com.google.zxing.client.result.ResultParser;
import com.whq.knowverywell.R;
import com.whq.knowverywell.activity.BaseLoginActivity;
import com.whq.knowverywell.activity.barcode.camera.CameraManager;
import com.whq.knowverywell.util.TipUtil;

/**
 * scan module
 * 
 * @author david
 */
public class BarcodeActivity extends BaseLoginActivity implements Callback {
    private static final String TAG = BarcodeActivity.class.getSimpleName();

	public static final class Scan {
		public static final String ACTION = "com.whq.knowverywell.david.barcode.SCAN";
		public static final String SCAN_FORMAT = "SCAN_FORMAT";
		public static final String URL = "URL";
		public static final String GAME = "GAME";
		public static final String ISBN = "ISBN";
		public static final String RESULT = "SCAN_RESULT";
		public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";

		private Scan() {
		}
	}

	private static final Set<ResultMetadataType> DISPLAYABLE_METADATA_TYPES;
	static {
		DISPLAYABLE_METADATA_TYPES = new HashSet<ResultMetadataType>(5);
		DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.ISSUE_NUMBER);
		DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.SUGGESTED_PRICE);
		DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.ERROR_CORRECTION_LEVEL);
		DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.POSSIBLE_COUNTRY);
	}

	private static final long INTENT_RESULT_DURATION = 100L;
	private static final long INTENT_LAUNCH_DURATION = 100L;
	private static final long RESTART_PREVIEW_DURATION = 1000L;

	private BarcodeActivityHandler handler;
	private boolean hasSurface;
	private Vector<BarcodeFormat> decodeFormats;
	private String characterSet;
	private InactivityTimer inactivityTimer;
	private boolean vibrate;
	private boolean scanResultMode;
	private String scanFormat;

	private ViewfinderView viewfinderView;
	private TextView statusView;
	private LinearLayout resultView;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		Log.d(TAG, "onCreate start ...");
		setTheme(R.style.Theme_Sherlock_Light_NoActionBar);
		super.onCreate(savedInstanceState);

		Window window = getWindow();
		window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		setContentView(R.layout.barcode);

		CameraManager.init(getApplication());

		viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
		statusView = (TextView) findViewById(R.id.status_view);
		resultView = (LinearLayout) findViewById(R.id.result_view);

		hasSurface = false;
		inactivityTimer = new InactivityTimer(this);

	}

	@Override
	protected void onResume() {
		Log.d(TAG, "onResume start ...");
		super.onResume();

		SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
		SurfaceHolder surfaceHolder = surfaceView.getHolder();
		if (hasSurface) {
			initCamera(surfaceHolder);
		} else {
			surfaceHolder.addCallback(this);
			surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		}
		
		decodeFormats = new Vector<BarcodeFormat>();
		decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
		decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
		decodeFormats.addAll(DecodeFormatManager.PRODUCT_FORMATS);
		decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
		
		characterSet = null;
		vibrate = true;

		Intent intent = getIntent();
		String action = intent == null ? null : intent.getAction();
		scanResultMode = action == null ? false : action.equals(Scan.ACTION);
		scanFormat = intent == null ? null : intent.getStringExtra(Scan.SCAN_FORMAT);

		inactivityTimer.onResume();
	}

	@Override
	protected void onPause() {
		super.onPause();
		if (handler != null) {
			handler.quitSynchronously();
			handler = null;
		}
		inactivityTimer.onPause();
		CameraManager.get().closeDriver();
	}

	@Override
	protected void onDestroy() {
		inactivityTimer.shutdown();
		super.onDestroy();
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			if (resultView.getVisibility() == View.GONE) {
				setResult(RESULT_CANCELED);
				finish();
			} else {
				resetStatusView();
				if (handler != null) {
					handler.sendEmptyMessage(R.id.restart_preview);
				}
			}
			return true;
		} else if (keyCode == KeyEvent.KEYCODE_MENU) {
			return true;
		} else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}

	private void initCamera(SurfaceHolder surfaceHolder) {
		try {
			CameraManager.get().openDriver(surfaceHolder);
			if (handler == null) {
				handler = new BarcodeActivityHandler(this, decodeFormats, characterSet);
			}
		} catch (IOException ioe) {
			Log.w(TAG, ioe);
			displayCameraErrorMessageAndExit();
			return;
		} catch (RuntimeException e) {
			Log.w(TAG, "Unexpected error initializating camera", e);
			displayCameraErrorMessageAndExit();
			return;
		}
	}

	private void displayCameraErrorMessageAndExit() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(getString(R.string.app_name));
		builder.setMessage(getString(R.string.barcode_msg_camera_error));
		builder.setPositiveButton(R.string.barcode_button_ok, new FinishListener(this));
		builder.setOnCancelListener(new FinishListener(this));
		builder.show();
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (!hasSurface) {
			hasSurface = true;
			initCamera(holder);
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		hasSurface = false;
	}

	public ViewfinderView getViewfinderView() {
		return viewfinderView;
	}

	public Handler getHandler() {
		return handler;
	}

	public void drawViewfinder() {
		viewfinderView.drawViewfinder();
	}

	private void restartPreview() {
		if (handler != null)
			handler.sendEmptyMessageDelayed(R.id.restart_preview, RESTART_PREVIEW_DURATION);
	}

	public void handleDecode(Result rawResult, Bitmap barcode) {
		inactivityTimer.onActivity();

		playVibrate();
		
		if (!isSupport(rawResult)) {
		    TipUtil.tipDescription(this, "不支持的条形码.");
		    restartPreview();
		}
		
		ParsedResult result = ResultParser.parseResult(rawResult);
		String productBarCode = result.getDisplayResult();
		
		Intent retData = new Intent();
		retData.putExtra(Scan.RESULT, productBarCode);
		setResult(RESULT_OK, retData);
		finish();
		
		
	}
	
	private boolean isSupport(Result rawResult) {
	    ParsedResult result = ResultParser.parseResult(rawResult);
	    if (ParsedResultType.URI.equals(result.getType())) {
	        return false;
        } else if (ParsedResultType.ISBN.equals(result.getType())) {
            return false;
        } else {
            return true;
        }
	}

	private static final long VIBRATE_DURATION = 200L;

	private void playVibrate() {
		if (vibrate) {
			Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
			vibrator.vibrate(VIBRATE_DURATION);
		}
	}

	private void resetStatusView() {
		resultView.setVisibility(View.GONE);
		statusView.setText(R.string.barcode_msg_tips);
		statusView.setVisibility(View.VISIBLE);
		viewfinderView.setVisibility(View.VISIBLE);
	}

	public static class BarcodeListener implements OnClickListener {
		@Override
		public void onClick(View v) {
			v.getContext().startActivity(new Intent(v.getContext(), BarcodeActivity.class));
		}
	}
}